#include "PanoramicDealProcess.h"

#include <core/Utility.h>
#include <qbkernel/include/qb_base.h>
#include <qbprotocol/include/MessageParserTool.h>
#include <qbprotocol/include/SSQBModel.h>
#include <qbprotocol/include/rdProto.h>

using namespace qb;

namespace {
#define Reg_Func(ID) \
  qbBase::getMessageBond()->RegisterDecodeFunc(ID, qbmsg::panoramic::ExtracFunc)
#define DelPtr(FUNC, TYPE)               \
  case FUNC: {                           \
    TYPE* p = static_cast<TYPE*>(toDel); \
    delete p;                            \
    return nullptr;                      \
  } break;

void* delAck(int func, void* toDel) {
  switch (func) {
    DelPtr(E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_REQ_V2,
           xQBPanoramicMarketStreamDealAck);
    DelPtr(E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_PUSH,
           xQBPanoramicMarketStreamDealAck);
    DelPtr(E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_REQ_V3,
           xQBPanoramicMarketStreamDealAck);
    DelPtr(E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_PUSH_V3,
           xQBPanoramicMarketStreamDealAck);
    DelPtr(E_FID_QB_DEAL_TERM_RANGE_OVERALL_REQ, xQBBondDealTermRgAck);
    DelPtr(E_FID_QB_DEAL_TERM_RANGE_OVERALL_MODIFY, xQBBondDealTermRgAck);
    default:
      break;
  }
  return toDel;
}

}  // namespace

void qbmsg::panoramic::InitDecodeFuncs() {
  Reg_Func(E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_REQ_V2);
  Reg_Func(E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_PUSH);
  Reg_Func(E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_REQ_V3);
  Reg_Func(E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_PUSH_V3);
  Reg_Func(E_FID_QB_DEAL_TERM_RANGE_OVERALL_REQ);
  Reg_Func(E_FID_QB_DEAL_TERM_RANGE_OVERALL_MODIFY);
}

void qbmsg::panoramic::EncodeFunc(qb::proto::Message& msg,
                                  qb::SSRequestMsg* req) {
  switch (req->m_FuncID) {
    case E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_REQ_V2:
    case E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_REQ_V3: {
      xQBPanoramicMarketStreamDealReq* pdata =
          (xQBPanoramicMarketStreamDealReq*)req->m_pRequest;
      qb::proto::VariantMap submsg;
      submsg.setInt32("IndexFrom", pdata->m_IndexFrom);
      submsg.setInt32("IndexTo", pdata->m_IndexTo);
      msg.SetMap("xQBPanoramicMarketStreamDealReq", submsg);
      break;
    }
    case E_FID_QB_DEAL_TERM_RANGE_OVERALL_REQ:
    case E_FID_QB_DEAL_TERM_RANGE_OVERALL_MODIFY: {
      xQBBondDealTermRgReq* pdata = (xQBBondDealTermRgReq*)req->m_pRequest;

      qb::proto::VariantMap msgReq;
      msgReq.SetString("UserId", pdata->m_UserId);
      msgReq.SetString("UserAccount", pdata->m_UserAccount);
      qb::proto::Message::List msgMatrix;
      for (auto itMatirx : pdata->m_matrixTerm) {
        qb::proto::VariantMap msgSubMatrix;
        msgSubMatrix.SetInt32("nRate", itMatirx.m_nRate);
        if (itMatirx.m_diffType >= 0)
          msgSubMatrix.SetInt32("diffType", itMatirx.m_diffType);
        qb::proto::Message::List msgListTerm;

        for (auto itListTerm : itMatirx.m_listTerm) {
          qb::proto::VariantMap msgSubListTerm;
          msgSubListTerm.setString("term", /*GBK2UTF8*/ (itListTerm.m_term));
          msgSubListTerm.setString("rangeLeft", itListTerm.m_rangeLeft);
          msgSubListTerm.setString("rangeRight", itListTerm.m_rangeRight);
          msgListTerm.push_back(msgSubListTerm);
        }

        msgSubMatrix.SetList("listTerm", msgListTerm);

        msgMatrix.push_back(msgSubMatrix);
      }
      msgReq.SetList("matrixTerm", msgMatrix);
      msg.SetMap("xQBBondDealTermRgReq", msgReq);
      break;
    }
    case E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_PUSH:
    case E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_PUSH_V3:
    default:
      break;
  }
}

void* qbmsg::panoramic::ExtracFunc(int func, const ProtoMessage& msg,
                                   void* toDel) {
  if (toDel != nullptr) return delAck(func, toDel);

  switch (func) {
    case E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_REQ_V2:
    case E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_REQ_V3: {
      static const char* bondkey = "bondkey";
      static const char* listedmarket = "listedmarket";
      static const char* bondCode = "bondCode";
      static const char* companyId = "companyId";
      static const char* dealStatus = "dealStatus";
      static const char* id = "id";
      static const char* price = "price";
      static const char* yield = "yield";
      static const char* cleanPrice = "cleanPrice";
      static const char* quotetype = "quotetype";
      static const char* operate = "operate";
      static const char* exercise = "exercise";
      static const char* updateTime = "updateTime";
      static const char* indexID = "indexID";
      static const char* Redemption_No = "Redemption_No";
      static const char* lastCloseYield = "lastCloseYield";
      static const char* lastClosecleanPrice = "lastClosecleanPrice";
      static const char* withinPeriodDeal = "withinPeriodDeal";
      static const char* listedFirstDeal = "listedFirstDeal";
      static const char* preAdv = "preAdv";

      qb::base::msg::Raw raw;
      if (!msg.GetRaw("List", raw)) return nullptr;

      xQBPanoramicMarketStreamDealAck* ptr =
          new xQBPanoramicMarketStreamDealAck;
      if (!ptr) return nullptr;

      qb::proto::VariantTableDecoder msglist;
      if (!msglist.decode((const char*)raw.Data, raw.Length)) return ptr;

      xQBPanoramicMarketStreamUnit unit;
      for (auto it = msglist.begin(); it != msglist.end(); ++it) {
        memset(&unit, 0, sizeof(unit));
        const qb::proto::VariantRecord* msgmap = *it;

        msgmap->getInt32(indexID, unit.m_indexID);
        CParserTool::MessageGetTime(msgmap, updateTime, unit.m_updateTime);
        FIELDCOPY(unit.m_bondCode, CParserTool::GetString(msgmap, bondCode));
        FIELDCOPY(unit.m_bondkey, CParserTool::GetString(msgmap, bondkey));
        FIELDCOPY(unit.m_listedmarket,
                  CParserTool::GetString(msgmap, listedmarket));
        FIELDCOPY(unit.m_companyId, CParserTool::GetString(msgmap, companyId));
        FIELDCOPY(unit.m_price, CParserTool::GetString(msgmap, price));
        FIELDCOPY(unit.m_cleanPrice,
                  CParserTool::GetString(msgmap, cleanPrice));
        FIELDCOPY(unit.m_yield, CParserTool::GetString(msgmap, yield));
        FIELDCOPY(unit.m_id, CParserTool::GetString(msgmap, id));
        FIELDCOPY(unit.m_dealStatus,
                  CParserTool::GetString(msgmap, dealStatus));
        FIELDCOPY(unit.m_preCloseYield,
                  CParserTool::GetString(msgmap, lastCloseYield));
        FIELDCOPY(unit.m_preClosecleanPrice,
                  CParserTool::GetString(msgmap, lastClosecleanPrice));
        FIELDCOPY(unit.m_withinPeriodDeal,
                  CParserTool::GetString(msgmap, withinPeriodDeal));
        FIELDCOPY(unit.m_listedFirstDeal,
                  CParserTool::GetString(msgmap, listedFirstDeal));
        FIELDCOPY(unit.m_preAdv, CParserTool::GetString(msgmap, preAdv));
        FIELDCOPY(unit.m_operate, CParserTool::GetString(msgmap, operate));
        FIELDCOPY(unit.m_quotetype, CParserTool::GetString(msgmap, quotetype));
        FIELDCOPY(unit.m_exercise, CParserTool::GetString(msgmap, exercise));
        msgmap->getInt32(Redemption_No, unit.m_Redemption_No);
        ptr->m_List.push_back(unit);
      }
      return ptr;
      break;
    }
    case E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_PUSH:
    case E_FID_QB_PANORAMIC_MARKET_STREAM_DEAL_PUSH_V3: {
      ProtoList msgList;
      if (!msg.getList("List", msgList)) return nullptr;

      xQBPanoramicMarketStreamDealAck* ptr =
          new xQBPanoramicMarketStreamDealAck;
      if (!ptr) return nullptr;

      xQBPanoramicMarketStreamUnit unit;
      for (ProtoList::const_iterator it = msgList.begin(); it != msgList.end();
           ++it) {
        if (it->Type != qb::proto::Variant::VAR_MAP) continue;
        memset(&unit, 0, sizeof(unit));
        const ProtoMap& msgmap = *it;
        msgmap.GetInt32("indexID", unit.m_indexID);
        CParserTool::MessageGetTime(msgmap, "updateTime", unit.m_updateTime);
        FIELDCOPY(unit.m_bondCode, CParserTool::GetString(msgmap, "bondCode"));
        FIELDCOPY(unit.m_bondkey, CParserTool::GetString(msgmap, "bondkey"));
        FIELDCOPY(unit.m_listedmarket,
                  CParserTool::GetString(msgmap, "listedmarket"));
        FIELDCOPY(unit.m_price, CParserTool::GetString(msgmap, "price"));
        FIELDCOPY(unit.m_cleanPrice,
                  CParserTool::GetString(msgmap, "cleanPrice"));
        FIELDCOPY(unit.m_yield, CParserTool::GetString(msgmap, "yield"));
        FIELDCOPY(unit.m_id, CParserTool::GetString(msgmap, "id"));
        FIELDCOPY(unit.m_dealStatus,
                  CParserTool::GetString(msgmap, "dealStatus"));
        FIELDCOPY(unit.m_preCloseYield,
                  CParserTool::GetString(msgmap, "lastCloseYield"));
        FIELDCOPY(unit.m_preClosecleanPrice,
                  CParserTool::GetString(msgmap, "lastClosecleanPrice"));
        FIELDCOPY(unit.m_withinPeriodDeal,
                  CParserTool::GetString(msgmap, "withinPeriodDeal"));
        FIELDCOPY(unit.m_listedFirstDeal,
                  CParserTool::GetString(msgmap, "listedFirstDeal"));
        FIELDCOPY(unit.m_companyId,
                  CParserTool::GetString(msgmap, "companyId"));
        FIELDCOPY(unit.m_preAdv, CParserTool::GetString(msgmap, "preAdv"));

        FIELDCOPY(unit.m_operate, CParserTool::GetString(msgmap, "operate"));
        FIELDCOPY(unit.m_quotetype,
                  CParserTool::GetString(msgmap, "quotetype"));
        FIELDCOPY(unit.m_exercise, CParserTool::GetString(msgmap, "exercise"));
        msgmap.GetInt32("Redemption_No", unit.m_Redemption_No);
        ptr->m_List.push_back(unit);
      }
      return ptr;
      break;
    }
    case E_FID_QB_DEAL_TERM_RANGE_OVERALL_REQ:
    case E_FID_QB_DEAL_TERM_RANGE_OVERALL_MODIFY: {
      ProtoList msgMatrix;
      if (!msg.GetList("matrixTerm", msgMatrix)) return nullptr;

      xQBBondDealTermRgAck* ptr = new xQBBondDealTermRgAck;
      if (!ptr) return nullptr;

      for (auto itMatrix = msgMatrix.begin(); itMatrix != msgMatrix.end();
           ++itMatrix) {
        const ProtoMap& msgSubMatrix = *itMatrix;
        sBondDealTermList unitMatrix;
        msgSubMatrix.GetInt32("nRate", unitMatrix.m_nRate);
        int diffType;
        if (msgSubMatrix.GetInt32("diffType", diffType)) {
          unitMatrix.m_diffType = diffType;
        }
        ProtoList msgListTerm;
        if (msgSubMatrix.GetList("listTerm", msgListTerm)) {
          for (ProtoList::const_iterator itListTerm = msgListTerm.begin();
               itListTerm != msgListTerm.end(); ++itListTerm) {
            const ProtoMap& msgSubListTerm = *itListTerm;
            sBondDealTermRgUnit unitTerm;
            FIELDCOPY(unitTerm.m_term,
                      CParserTool::GetString(msgSubListTerm, "term"));
            FIELDCOPY(unitTerm.m_rangeLeft,
                      CParserTool::GetString(msgSubListTerm, "rangeLeft"));
            FIELDCOPY(unitTerm.m_rangeRight,
                      CParserTool::GetString(msgSubListTerm, "rangeRight"));
            unitMatrix.m_listTerm.push_back(unitTerm);
          }
        }
        ptr->m_matrixTerm.push_back(unitMatrix);
      }
      return ptr;
      break;
    }
    default:
      break;
  }

  return nullptr;
}
